iT邦幫忙

2024 iThome 鐵人賽

DAY 2
0
JavaScript

Signal API in Angular系列 第 2

Day 02 - 使用基本構建塊建立 Angular 應用程式

  • 分享至 

  • xImage
  •  

在接下來的幾天深入研究 Signal API 之前,我想建立一個簡單的 Angular 應用程式來顯示所有 100 個貼文。 該應用程式演示了該框架的基本構建塊:

  • 顯示單一貼文和貼文清單的組件
  • 為組件傳回帖子數組以顯示資料的服務
  • HTML 模板和 CSS 樣式用於更新字體樣式、邊距和填充
  • 當使用者與元件的 HTML 元素互動時發生的事件發射器
  • 輸入,智慧組件將資料傳遞給啞組件以顯示動態內容

現在,我將透過定義 TypeScript 類型、服務和幾個元件來完成逐步教學。 請按照第一天的說明在瀏覽器上建立一個新的 Angular 專案。

建立類型

我們的組件在列表中顯示貼文;因此,使用 Post 類型來進行類型安全和類型檢查是一個很好的做法。在檔案總管中,在 src 資料夾下新增一個名為 post.type.ts 的檔案。

// post.type.ts

export type Post = {
 id: number;
 userId: number;
 title: string;
 body: string;
};

新增Post Service

服務負責在 Angular 中取得和管理資料。在此範例中,PostService 提供了記憶體中的 Post 物件陣列。元件可以注入此服務來存取貼文並將其顯示在 UI 中。

// post.service.ts 

import { Injectable } from '@angular/core';
import { Post } from './post.type';

@Injectable({
 providedIn: 'root'
})
export class PostService {
 posts: Post[] = [
   {
     "userId": 1,
     "id": 1,
     "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
     "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
   },
   {
     "userId": 1,
     "id": 2,
     "title": "qui est esse",
     "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"
   },
   ... omit the next 98 Post objects ...
 ]
}

然後,任何組件都可以注入PostService服務來存取posts陣列。

組件架構

Angular採用組件架構,即將一個大組件分解為幾個小組件,以便於維護、可讀性、協作性和良好的性能。

App
|----- PostsComponent
          |-----------PostComponent

建立貼文組件

讓我們建立一個代表單一貼文的PostComponent。在src資料夾下,建立一個PostComponent類別。

// post.component.ts

import { ChangeDetectionStrategy, Component, input, output } from "@angular/core";
import { Post } from "./post.type";

@Component({
 selector: 'app-post',
 standalone: true,
 template: `
   <p><span class="text">Id: </span>{{ post().id }}</p>
   <p><span class="text">Title: </span>{{ post().title }}</p>
   <p><span class="text">Body: </span>{{ post().body }}</p>
   <button (click)="deleteClicked.emit(post().id)">Delete</button>
   <hr />
 `,
 styles: `
   .text {
     font-style: italic;
     color: #a4a4a4;
   }

   button {
     margin-bottom: 0.5rem;
   }
 `,
 changeDetection: ChangeDetectionStrategy.OnPush,
})
export class PostComponent {
 post = input.required<Post>();
 deleteClicked = output<number>();
}
selector: 'app-post',
standalone: true,

組件標籤為 <app-post [post]="post" (deleteClicked)="..." />,它是一個獨立的組件。

template: `
   <p><span class="text">Id: </span>{{ post().id }}</p>
   <p><span class="text">Title: </span>{{ post().title }}</p>
   <p><span class="text">Body: </span>{{ post().body }}</p>
   <button (click)="deleteClicked.emit(post().id)">Delete</button>
   <hr />
 `,

HTML範本顯示貼文的 ID、標題、內文以及點擊後刪除目前貼文的按鈕。 該按鈕還說明了一個稱為事件發射 (event emitter) 的重要概念,該概念將事件資料發射到包含它的組件。

(click)="deleteClicked.emit(post().id)"

按鈕點擊事件將貼文 ID 傳送到其父組件(即 PostsComponent)。

styles: `
   .text {
     font-style: italic;
     color: #a4a4a4;
   }

   button {
     margin-bottom: 0.5rem;
   }
 `

套用於HTML範本的按鈕和span elements的CSS樣式。

export class PostComponent {
 post = input.required<Post>();
 deleteClicked = output<number>();
}

該組件有一個post輸入,它是一個Signal輸入(Signal和Signal輸入將在本系列中詳細解釋),而 deleteClicked 是一個自訂事件,它向parent component發出事件資料。

https://ithelp.ithome.com.tw/upload/images/20240811/20168314xpKX3LpeYL.png

建立貼文清單組件

讓我們建立一個由PostComponent組成的PostsComponent

import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
import 'zone.js';
import { PostService } from './post.service';
import { PostComponent } from './post.component';

@Component({
 selector: 'app-posts',
 standalone: true,
 imports: [PostComponent],
 template: `
   <div>
     <p>Number of posts: {{ filteredPosts.length }}</p>
     <button (click)="restore()">Restore</button>
   </div>
   @for (post of filteredPosts; track post.id) { 
     <app-post [post]="post" (deleteClicked)="delete($event)" />
   }
 `,
 styles: `
   div {
     display: flex;
     align-items: center;
   }

   div > p {
     margin-right: 0.5rem;
   }
 `,
 changeDetection: ChangeDetectionStrategy.OnPush,
})
export class PostsComponent {
 postService = inject(PostService);
 filteredPosts = [...this.postService.posts];

 delete(id: number) {
   this.filteredPosts = this.filteredPosts.filter((post) => post.id !== id);
 }

 restore() {
   this.filteredPosts = [...this.postService.posts];
 }
}
imports: [PostComponent],

PostsComponent匯入PostComponent以在清單中顯示資料。

template: `
   <div>
     <p>Number of posts: {{ filteredPosts.length }}</p>
     <button (click)="restore()">Restore</button>
   </div>
   @for (post of filteredPosts; track post.id) { 
     <app-post [post]="post" (deleteClicked)="delete($event)" />
   }
 `,

HTML範本使用@for內建控制項來渲染<app-post>並顯示所有貼文。<app-post>接收Post輸入並發出deleteClicked自訂事件以呼叫delete方法來修改filteredPosts陣列。 HTML按鈕元素的clicked事件執行restore方法以重設所有貼文。

postService = inject(PostService);
filteredPosts = [...this.postService.posts];

該組件透過依賴注入來注入PostServicefilteredPosts變數spread(...) this.postService.posts以複製Post陣列。

delete(id: number) {
   this.filteredPosts = this.filteredPosts.filter((post) => post.id !== id);
 }

restore() {
   this.filteredPosts = [...this.postService.posts];
}

delete方法刪除具有匹配id的貼文,restore方法會建立filteredPosts變數的新副本。

https://ithelp.ithome.com.tw/upload/images/20240811/20168314b6j8ojI15S.png

import { Component } from '@angular/core';
import { PostsComponent } from './posts.component';

@Component({
 selector: 'app-root',
 standalone: true,
 imports: [PostsComponent],
 template: `
   <h1>Hello from {{ name }}!</h1>
   <h2>Posts List</h2>
   <app-posts />
 `,
})
export class App {
 name = 'IT Home Ironman 2024 day 2';
}

App組件使用PostsComponent組件來顯示貼文清單。

最終的應用程式

https://ithelp.ithome.com.tw/upload/images/20240811/20168314cPKvBu2eEg.png

Angular Playground

如果您對Angular感興趣,Angular團隊提供了可以在Playground或電腦上運行的教學。

結論

  • 簡而言之,使用以下命令建立 Angular 應用程式
    • 組件
    • 服務
    • HTML範本和 CSS 樣式
    • 自訂事件
    • 輸入
  • 造訪Angular Playground,這是一個從頭開始在線上建立應用程式的綜合教學。

鐵人賽的第二天就到此結束。

參考:


上一篇
Day 01 - Angular:從基礎知識到 Signal API
下一篇
Day 03 - Angular 的 Signal API
系列文
Signal API in Angular10
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
peace&love
iT邦新手 5 級 ‧ 2024-08-14 10:28:29

好棒!就想看這個 3Q
這是用ai寫的嗎

I wrote all my blog posts in English and then used Google Translate to translate the paragraphs.

我所有的部落格文章都是用英語寫的,然後使用谷歌翻譯來翻譯這些段落。

有在FB社團看到了XD
你在國外工作?國外專案有開始用signal了嗎?
請繼續分享~ 感恩!

我要留言

立即登入留言